import os, re, m3u8, ffmpy, yaml
import urllib.request as req
from concurrent.futures import ThreadPoolExecutor
from Crypto.Cipher import AES

work_path = os.path.dirname(__file__)
def load_config(config_file):
    with open(config_file, 'r', encoding='utf-8') as f:
        return yaml.safe_load(f)

def config_ini():
    return {
        'FFmpeg': True,
        'ff_address': 'D:\\Program Files\\FFmpeg\\bin\\ffmpeg.exe',
        'n_digit': 5,
        'n_start': 0,
        'port_name': '诺讯解析',
        'ports': {
            '1717 云_1': 'https://www.1717yun.com/1717yun/?url=',
            '1717 云_2': 'http://www.1717yun.com/jx/ty.php?url=',
            '8090_1': 'https://www.8090g.cn/?url=',
            '8090_2': 'https://www.8090.la/8090/?url=',
            '973 播放器': 'https://jx.973973.xyz/?url=',
            'B 站解析': 'https://jx.bozrc.com:4433/player/?url=',
            'CK MOV': 'https://www.ckmov.vip/api.php?url=',
            'CK Player': 'https://www.ckplayer.vip/jiexi/?url=',
            'H8 解析': 'https://www.h8jx.com/jiexi.php?url=',
            'Ivito': 'http://jx.ivito.cn/?url=',
            'JY 解析_1 (有广告)': 'https://jx.we-vip.com/?url=',
            'JY 解析_2 (有广告)': 'https://jx.playerjy.com/?url=',
            'Json Player (嗅探不到)': 'https://jx.bozrc.com:4433/player/?url=',
            'M2090': 'https://m2090.com/?url=',
            'Mao Player': 'https://www.mtosz.com/m3u8.php?url=',
            'OK 解析': 'https://okjx.cc/?url=',
            'OK 解析 api': 'https://api.okjx.cc:3389/jx.php?url=',
            'Play m3u8': 'https://www.playm3u8.cn/jiexi.php?url=',
            'm3u8 TV': 'https://jx.m3u8.tv/jiexi/?url=',
            '云解析_1 (嗅探不到)': 'http://jx.ppflv.com/?url=',
            '云解析_2 (嗅探不到)': 'https://jx.aidouer.net/?url=',
            '云解析_盘古 (嗅探不到)': 'https://go.yh0523.cn/y.cy?url=',
            '冰豆解析': 'https://api.qianqi.net/vip/?url=',
            '夜幕': 'https://www.yemu.xyz/?url=',
            '无名小站': 'https://www.administratorw.com/video.php?url=',
            '玩得嗨 (不稳定)': 'http://vip.wandhi.com/?v=',
            '盘古解析_1': 'https://www.pangujiexi.com/jiexi/?url=',
            '盘古解析_2': 'https://www.pangujiexi.cc/jiexi.php?url=',
            '解析啦': 'https://api.jiexi.la/?url=',
            '诺讯解析': 'https://www.nxflv.com/?url='
        },
        'threads': 30,
        'time_out': 10,
        'video_name': 'Video'
    }

def analyze_m3u8(m3u8_address):
    video = m3u8.load(m3u8_address)
    if m3u8_address.startswith('http'):
        url_prefix = os.path.split(m3u8_address)[0] + '/'
    else:
        url_prefix = ''

    if video.keys == [None]:
        cryptor = None
    else:
        key_info = video.keys[0]
        key_url = key_info.uri
        if key_url.startswith('http'):
            url_prefix = os.path.split(key_url)[0] + '/'
        else:
            key_url = url_prefix + os.path.split(key_url)[1]
        key = req.urlopen(key_url).read()
        cryptor = AES.new(key, AES.MODE_CBC, key)

    urls = video.segments.uri
    if not urls[0].startswith('http'):
        urls = [url_prefix + os.path.split(url)[1] for url in urls]
        
    return urls, cryptor

def analyze_segment(address, n_digit, Start=0, TimeOut=10):
    url_0 = os.path.splitext(address)[0][:-n_digit]
    ext = os.path.splitext(address)[1]
    
    def find_stop():
        a, b = 0, 1000
        print('Finding stop_max ...')
        while True:
            url = url_0 + str(b).zfill(n_digit) + ext
            try:
                req.urlopen(url, timeout=TimeOut)
                a = b
                b = 2 * b
            except Exception as e:
                if str(e).__contains__('403') or str(e).__contains__('404'):
                    break
                else:
                    print(e)
        
        print('Approaching stop ...')
        while b - a > 1:
            i = int((a + b)/2)
            url = url_0 + str(i).zfill(n_digit) + ext
            try:
                req.urlopen(url, timeout=TimeOut)
                a = i
            except Exception as e:
                if str(e).__contains__('403') or str(e).__contains__('404'):
                    b = i
                else:
                    print(e)
        print('stop = %s' %b)
        return b
    
    stop = find_stop()
    urls = [url_0 + str(i).zfill(n_digit) + ext for i in range(Start, stop)]
    return urls

# Define download (list)
def download(url, name, Cryptor=None, TimeOut=10):
    try:
        res = req.urlopen(url, timeout=TimeOut)
        with open(name, 'wb') as file:
            if Cryptor == None:
                file.write(res.read())
            else:
                file.write(Cryptor.decrypt(res.read()))
        print(name + ' downloaded')
    except Exception as e:
        if str(e).__contains__('403') or str(e).__contains__('404'):
            print(name + ' Error: %s'%e)
        else:
            print(name + ' Error: %s'%e)
            download(url, name, Cryptor, TimeOut)
def list_download(folder_name, url_list, Threads=50, Cryptor=None, TimeOut=10):
    with ThreadPoolExecutor(max_workers=Threads) as executor:
        for url in url_list:
            file_name = '{0}\\{0}_{1}.ts'.format(folder_name, str(url_list.index(url)))
            executor.submit(download, url, file_name, Cryptor, TimeOut)
        executor.shutdown(wait=True)
def list_index_download(folder_name, url_list, index_list, Threads=50, Cryptor=None, TimeOut=10):
    with ThreadPoolExecutor(max_workers=Threads) as executor:
        for i in index_list:
            file_name = '{0}\\{0}_{1}.ts'.format(folder_name, str(i))
            executor.submit(download, url_list[i], file_name, Cryptor, TimeOut)
        executor.shutdown(wait=True)

# Check incomplete items
def index_na(folder_name, index_list):
    files = os.listdir(folder_name)
    index = [int(re.findall('\d+(?=\.)', i)[-1]) for i in files]
    return [i for i in index_list if i not in index]
def check_0(folder_name):
    files = os.listdir(folder_name)
    return [int(re.findall('\d+(?=\.)', i)[-1]) for i in files if os.path.getsize(folder_name + '\\' + i) == 0]

# Merge videos
def FFmpeg_merge(folder_name, ff_exe = 'ffmpeg'):
    files = os.listdir(folder_name)
    files.sort(key=lambda x: int(re.findall('\d+(?=\.)', x)[-1]))
    files = ["file '%s'\n" %(folder_name + '/' + i) for i in files]
    file_list = 'FileList.txt'
    with open(file_list, 'w', encoding='utf-8') as f:
        f.writelines(files)
    ff = ffmpy.FFmpeg(
        executable=ff_exe,
        global_options='-y -hide_banner',
        inputs={file_list:'-f concat -safe 0'},
        outputs={folder_name+'.mp4':'-c copy'}
    )
    print(ff.cmd)
    ff.run()
    os.remove(file_list)
    print('Merge finished.')

def merge(folder_name):
    files = os.listdir(folder_name)
    files.sort(key=lambda x: int(re.findall('\d+(?=\.)', x)[-1]))
    ext = os.path.splitext(files[0])[1]
    file_name = folder_name + ext
    with open(file_name, 'wb') as f:
        pass
    for i in files:
        with open(folder_name + '\\' + i, 'rb') as f:
            cont = f.read()
        with open(file_name, 'ab') as f:
            f.write(cont)
    print('Merge finished.')